using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace Decav.Transactions
{
    /// <summary>
    /// Finds a public get/set property with the same name as the source property to
    /// bind with.
    /// </summary>
    public class PublicPropertyBindingTargetSelector : IBindingTargetSelector
    {
        /// <summary>
        /// Initializes a new <see cref="PublicPropertyBindingTargetSelector"/>
        /// instance.
        /// </summary>
        /// <param name="throwWhenNotFound">Specifies if an exception will be thrown
        /// if a bind target is not found.</param>
        public PublicPropertyBindingTargetSelector(bool throwWhenNotFound)
        {
            _throwWhenNotFound = throwWhenNotFound;
        }

        private bool _throwWhenNotFound;

        /// <summary>
        /// Gets if an exception will be thrown if a bind target is not found.
        /// </summary>
        public bool ThrowWhenNotFound
        {
            get
            {
                return _throwWhenNotFound;
            }
        }

        #region IBindingTargetSelector Members

        public BindingTarget FindTarget(object targetObject, BindingTarget source)
        {
            if (targetObject == null)
                throw new ArgumentNullException("targetObject");

            if (source == null)
                throw new ArgumentNullException("source");

            PropertyInfo prop = targetObject.GetType().GetProperty(source.Member.Name, PublicPropertyBoundPropertiesSelector._publicPropConstant);

            if (prop == null)
            {
                if (ThrowWhenNotFound)
                    throw new DataBindException(string.Format("The property '{0}' cannot be bound to object of type '{1}' because a property with the same name could not be found.",
                        source.Member.Name, targetObject.GetType().FullName));
                else
                    return null;
            }

            return new BindingTarget(targetObject, prop,
                PublicPropertyBoundPropertiesSelector.GetChangedEvent(targetObject.GetType(), prop));    
        }

        #endregion
    }
}
